package com.batsoft.trade.api.core.shiro.manage;

import com.gomyb.redis.RedisService;
import com.gomyb.web.SpringContextUtil;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.ShiroException;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;

/**
 * @author <a href="mailto:hellohesir@gmail.com">Mr_He</a>
 * 2019/7/18 14:57
 */
@Slf4j
public class RedisSessionDao extends AbstractSessionDAO {

    @Override
    protected Serializable generateSessionId(Session session) {
        return super.generateSessionId(session);
    }

    public RedisSessionDao(int timeOut) {
        this.timeOut = timeOut;
    }

    @Setter
    private int timeOut;

    @Autowired
    private RedisService redisService;

    private static final ThreadLocal<Map<String, SessionDto>> sessionLocal = new ThreadLocal<>();

    @Override
    protected Serializable doCreate(Session session) {
        if (session == null) {
            doCreate(new SimpleSession());
            log.error("session is null");
        }
        HttpServletRequest request = SpringContextUtil.getRequest();
        String token = request.getHeader(ShiroConstant.AUTHORIZATION);
        Serializable sessionId;
        if (StringUtils.isNotBlank(token)) {
            sessionId = token;
        } else {
            sessionId = generateSessionId(session);
        }
        this.assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    private void saveSession(Session session) {
        if (null != session && null != session.getId()) {
            if (null == sessionLocal.get()) {
                Map<String, SessionDto> map = new HashMap<>();
                sessionLocal.set(map);
            }
            SessionDto sessionDto = new SessionDto();
            sessionDto.setSession(session);
            sessionLocal.get().put(session.getId().toString(), sessionDto);
            redisService.setObj(ShiroConstant.SESSION_PREFIX + session.getId(), session, timeOut);
            return;
        }
        throw new ShiroException("session save exception");
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (null == sessionId) {
            return null;
        }
        Map<String, SessionDto> map = sessionLocal.get();
        if (map == null) {
            map = new HashMap<>();
            sessionLocal.set(map);
        }
        /*SessionDto sessionDto = sessionLocal.get().get(sessionId.toString());
        if (null != sessionDto) {
            return sessionDto.getSession();
        }*/
        Session session = redisService.getObj(ShiroConstant.SESSION_PREFIX + sessionId);
        if (null == session) {
            this.doCreate(new SimpleSession());
        }
        SessionDto dto = new SessionDto();
        dto.setSession(session);
        sessionLocal.get().put(sessionId.toString(), dto);
        return session;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    @Override
    public void delete(Session session) {
        sessionLocal.get().remove(session.getId().toString());
        redisService.del(ShiroConstant.SESSION_PREFIX + session.getId());
    }

    @Override
    public Collection<Session> getActiveSessions() {
        List<Session> sessions = new ArrayList<>();
        /*try {
            Collection<SessionDto> sessionDtos = sessionLocal.get().values();
            for (SessionDto sessionDto : sessionDtos) {
                sessions.add(sessionDto.getSession());
            }
            return sessions;
        } catch (Exception ignored) {
        }*/
        Set<String> keys = redisService.keys(ShiroConstant.SESSION_PREFIX + "*");
        for (String key : keys) {
            try {
                Session session = redisService.getObj(key);
                if (null != session)
                    sessions.add(session);
            } catch (Exception ignored) {
            }
        }
        return sessions;
    }
}
